// SpMapNumber.cpp : Defines the entry point for the DLL application.
//

#include "stdafx.h"
#include "SpMapNumber.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <math.h>

void GetGBNewMapName(MAPSCALE eScale, double lat, double lon, char* pszMapName)
{
	int n1, n2, n3, n4, n5;
	n1 = n2 = n3 = n4 = n5 = 0;
	
	n1 = int(floor(lat/4)) + 1;
	n2 = int(floor(lon/6)) + 31;

	double dLat, dLon;
	GetMapSize(eScale, &dLat, &dLon);

	n3 = eScale;
	n4 = int(4.0/dLat+0.01)-int(floor((lat - (n1-1)*4.0f)/dLat));
	n5 = int(floor((lon - int(floor(lon/6.0f))*6.0f)/dLon))+1;
	
	sprintf(pszMapName, "%c%2d%c%03d%03d", 'A'+n1-1, n2, 'A'+n3, n4, n5);
}

void GetGBOldMapName(MAPSCALE eScale, double lat, double lon, char* pszMapName)
{
	if (lat < 0)
	{
		*pszMapName = '\0';
		return;
	}

	int n1, n2, n3, n4, n5, n6, n7;
	n1 = n2 = n3 = n4 = n5 = n6 = n7 = 0;;

	n1 = int(floor(lat/4)) + 1;
	n2 = int(floor(lon/6)) + 31;

	double dLat = 0, dLon = 0;
	int row = 0, col = 0;

	double lat1, lon1;
	lat1 = lat - 4*(n1-1);
	lon1 = lon - 6*(n2-31);
	
	switch (eScale)
	{
	case MS_1000000:
		{
			sprintf(pszMapName, "%c-%d", 'A'+n1-1, n2);
		}
		break;
	case MS_500000:
		{
			GetMapSize(eScale, &dLat, &dLon);
			row = 2-int(floor(lat1/dLat));
			col = int(floor(lon1/dLon)) + 1;
			n3  = 2*(row-1) + col;
			sprintf(pszMapName, "%c-%d-%c", 'A'+n1-1, n2, n3+'A'-1);
		}
		break;
	case MS_250000:
		{
			GetMapSize(eScale, &dLat, &dLon);
			row = 4-int(floor(lat1/dLat));
			col = int(floor(lon1/dLon)) + 1;
			n3  = 4*(row-1) + col;
			sprintf(pszMapName, "%c-%d-[%d]", 'A'+n1-1, n2, n3);
		}
		break;
	case MS_100000:
		{
			GetMapSize(eScale, &dLat, &dLon);
			row = 12-int(floor(lat1/dLat));
			col = int(floor(lon1/dLon)) + 1;
			n3  = 12*(row-1) + col;
			sprintf(pszMapName, "%c-%d-%d", 'A'+n1-1, n2, n3);
		}
		break;
	case MS_50000:
		{
			GetMapSize(MS_100000, &dLat, &dLon);
			row = int(floor(lat1/dLat));
			col = int(floor(lon1/dLon));
			lat1 -= row*dLat;
			lon1 -= col*dLon;

			row = 12-row;
			n3  = 12*(row-1) + col+1;

			GetMapSize(MS_50000, &dLat, &dLon);
			row = 2-int(floor(lat1/dLat));
			col = int(floor(lon1/dLon));
			n4  = 2*(row-1) + col+1;

			sprintf(pszMapName, "%c-%d-%d-%c", 'A'+n1-1, n2, n3, n4+'A'-1);
		}
		break;
	case MS_25000:
		{
			// 10W
			GetMapSize(MS_100000, &dLat, &dLon);
			row = int(floor(lat1/dLat));
			col = int(floor(lon1/dLon));
			lat1 -= row*dLat;
			lon1 -= col*dLon;
			
			row = 12-row;
			n3  = 12*(row-1) + col+1;
			
			// 5W
			GetMapSize(MS_50000, &dLat, &dLon);
			row = int(floor(lat1/dLat));
			col = int(floor(lon1/dLon));

			lat1 -= row*dLat;
			lon1 -= col*dLon;

			row = 2-row;
			n4  = 2*(row-1) + col+1;

			// 2.5W
			GetMapSize(MS_25000, &dLat, &dLon);
			row = int(floor(lat1/dLat));
			col = int(floor(lon1/dLon));

			row = 2-row;
			n5  = 2*(row-1) + col+1;
			
			sprintf(pszMapName, "%c-%d-%d-%c-%d", 'A'+n1-1, n2, n3, n4+'A'-1, n5);	
		}
		break;
	case MS_10000:
		{
			// 10W
			GetMapSize(MS_100000, &dLat, &dLon);
			row = int(floor(lat1/dLat));
			col = int(floor(lon1/dLon));
			lat1 -= row*dLat;
			lon1 -= col*dLon;
			
			row = 12-row;
			n3  = 12*(row-1) + col+1;

			// 1W
			GetMapSize(MS_10000, &dLat, &dLon);
			row = int(floor(lat1/dLat));
			col = int(floor(lon1/dLon));

			row = 8-row;
			n4  = 8*(row-1) + col+1;
			
			sprintf(pszMapName, "%c-%d-%d-(%d)", 'A'+n1-1, n2, n3, n4);
		}
		break;
	case MS_5000:
		{
			// 10W
			GetMapSize(MS_100000, &dLat, &dLon);
			row = int(floor(lat1/dLat));
			col = int(floor(lon1/dLon));
			lat1 -= row*dLat;
			lon1 -= col*dLon;
			
			row = 12-row;
			n3  = 12*(row-1) + col+1;
						
			// 1W
			GetMapSize(MS_10000, &dLat, &dLon);
			row = int(floor(lat1/dLat));
			col = int(floor(lon1/dLon));

			lat1 -= row*dLat;
			lon1 -= col*dLon;
			
			row = 8-row;
			n4  = 8*(row-1) + col+1;

			// 5000
			GetMapSize(MS_5000, &dLat, &dLon);
			row = int(floor(lat1/dLat));
			col = int(floor(lon1/dLon));

			row = 2-row;
			n5  = 2*(row-1) + col+1;
			
			sprintf(pszMapName, "%c-%d-%d-(%d)-%c", 'A'+n1-1, n2, n3, n4, n5+'a'-1);
		}
		break;
	default:
		{
			strcpy(pszMapName, "");
		}
		break;
	}
}

void GetGJBMapName(MAPSCALE eScale, double lat, double lon, char* pszMapName)
{
	if (lat < 0)
	{
		*pszMapName = '\0';
		return;
	}

	int n1, n2, n3, n4, n5, n6, n7;
	n1 = n2 = n3 = n4 = n5 = n6 = n7 = 0;;

	n1 = int(floor(lat/4)) + 1;
	n2 = int(floor(lon/6)) + 31;

	double dLat = 0, dLon = 0;
	int row = 0, col = 0;

	double lat1, lon1;
	lat1 = lat - 4*(n1-1);
	lon1 = lon - 6*(n2-31);
	
	switch (eScale)
	{
	case MS_1000000:
		{
			sprintf(pszMapName, "%d-%d", n1, n2);
		}
		break;
	case MS_500000:
		{
			GetMapSize(eScale, &dLat, &dLon);
			row = 2-int(floor(lat1/dLat));
			col = int(floor(lon1/dLon)) + 1;
			n3  = 2*(row-1) + col;
			sprintf(pszMapName, "%d-%d-%c", n1, n2, n3+'A'-1);
		}
		break;
	case MS_250000:
		{
			GetMapSize(eScale, &dLat, &dLon);
			row = 4-int(floor(lat1/dLat));
			col = int(floor(lon1/dLon)) + 1;
			n3  = 4*(row-1) + col;
			sprintf(pszMapName, "%d-%d-[%d]", n1, n2, n3);
		}
		break;
	case MS_100000:
		{
			GetMapSize(eScale, &dLat, &dLon);
			row = 12-int(floor(lat1/dLat));
			col = int(floor(lon1/dLon)) + 1;
			n3  = 12*(row-1) + col;
			sprintf(pszMapName, "%d-%d-%d", n1, n2, n3);
		}
		break;
	case MS_50000:
		{
			GetMapSize(MS_100000, &dLat, &dLon);
			row = int(floor(lat1/dLat));
			col = int(floor(lon1/dLon));
			lat1 -= row*dLat;
			lon1 -= col*dLon;

			row = 12-row;
			n3  = 12*(row-1) + col+1;

			GetMapSize(MS_50000, &dLat, &dLon);
			row = 2-int(floor(lat1/dLat));
			col = int(floor(lon1/dLon));
			n4  = 2*(row-1) + col+1;

			sprintf(pszMapName, "%d-%d-%d-%c", n1, n2, n3, n4+'A'-1);
		}
		break;
	case MS_25000:
		{
			// 10W
			GetMapSize(MS_100000, &dLat, &dLon);
			row = int(floor(lat1/dLat));
			col = int(floor(lon1/dLon));
			lat1 -= row*dLat;
			lon1 -= col*dLon;
			
			row = 12-row;
			n3  = 12*(row-1) + col+1;
			
			// 5W
			GetMapSize(MS_50000, &dLat, &dLon);
			row = int(floor(lat1/dLat));
			col = int(floor(lon1/dLon));

			lat1 -= row*dLat;
			lon1 -= col*dLon;

			row = 2-row;
			n4  = 2*(row-1) + col+1;

			// 2.5W
			GetMapSize(MS_25000, &dLat, &dLon);
			row = int(floor(lat1/dLat));
			col = int(floor(lon1/dLon));

			row = 2-row;
			n5  = 2*(row-1) + col+1;
			
			sprintf(pszMapName, "%d-%d-%d-%c-%d", n1, n2, n3, n4+'A'-1, n5);	
		}
		break;
	case MS_10000:
		{
			// 10W
			GetMapSize(MS_100000, &dLat, &dLon);
			row = int(floor(lat1/dLat));
			col = int(floor(lon1/dLon));
			lat1 -= row*dLat;
			lon1 -= col*dLon;
			
			row = 12-row;
			n3  = 12*(row-1) + col+1;
			
			// 5W
			GetMapSize(MS_50000, &dLat, &dLon);
			row = int(floor(lat1/dLat));
			col = int(floor(lon1/dLon));
			
			lat1 -= row*dLat;
			lon1 -= col*dLon;
			
			row = 2-row;
			n4  = 2*(row-1) + col+1;
			
			// 2.5W
			GetMapSize(MS_25000, &dLat, &dLon);
			row = int(floor(lat1/dLat));
			col = int(floor(lon1/dLon));

			lat1 -= row*dLat;
			lon1 -= col*dLon;
			
			row = 2-row;
			n5  = 2*(row-1) + col+1;

			// 1W
			GetMapSize(MS_10000, &dLat, &dLon);
			row = int(floor(lat1/dLat));
			col = int(floor(lon1/dLon));

			row = 2-row;
			n6  = 2*(row-1) + col+1;
			
			sprintf(pszMapName, "%d-%d-%d-%c-%d-(%d)", n1, n2, n3, n4+'A'-1, n5, n6);
		}
		break;
	case MS_5000:
		{
			// 10W
			GetMapSize(MS_100000, &dLat, &dLon);
			row = int(floor(lat1/dLat));
			col = int(floor(lon1/dLon));
			lat1 -= row*dLat;
			lon1 -= col*dLon;
			
			row = 12-row;
			n3  = 12*(row-1) + col+1;
			
			// 5W
			GetMapSize(MS_50000, &dLat, &dLon);
			row = int(floor(lat1/dLat));
			col = int(floor(lon1/dLon));
			
			lat1 -= row*dLat;
			lon1 -= col*dLon;
			
			row = 2-row;
			n4  = 2*(row-1) + col+1;
			
			// 2.5W
			GetMapSize(MS_25000, &dLat, &dLon);
			row = int(floor(lat1/dLat));
			col = int(floor(lon1/dLon));
			
			lat1 -= row*dLat;
			lon1 -= col*dLon;
			
			row = 2-row;
			n5  = 2*(row-1) + col+1;
			
			// 1W
			GetMapSize(MS_10000, &dLat, &dLon);
			row = int(floor(lat1/dLat));
			col = int(floor(lon1/dLon));

			lat1 -= row*dLat;
			lon1 -= col*dLon;
			
			row = 2-row;
			n6  = 2*(row-1) + col+1;

			// 5000
			GetMapSize(MS_5000, &dLat, &dLon);
			row = int(floor(lat1/dLat));
			col = int(floor(lon1/dLon));

			row = 2-row;
			n7  = 2*(row-1) + col+1;
			
			sprintf(pszMapName, "%d-%d-%d-%c-%d-(%d)-(%c)", n1, n2, n3, n4+'A'-1, n5, n6, n7+'a'-1);
		}
		break;
	case MS_2000:
		{
			MapInfo info; memset(&info, 0, sizeof(MapInfo));
			info.format = MF_GBNEW;
			info.scale  = MS_5000;
			GetMapInfo(lat, lon, &info);

			lat1 = lat - info.Lat0;
			lon1 = lon - info.Lon0;

			GetMapSize(MS_2000, &dLat, &dLon);
			row = int(floor(lat1/dLat));
			col = int(floor(lon1/dLon));

			row = 3-row;
			n6  = 3*(row-1) + col+1;

			sprintf(pszMapName, "%s-%d", info.pszName, n6);
		}
		break;
	}	
}

void GetGJBNewMapName(MAPSCALE eScale, double lat, double lon, char* pszMapName)
{
	if (lat < 0)
	{
		*pszMapName = '\0';
		return;
	}
	
	int n1, n2, n3, n4, n5, n6, n7;
	n1 = n2 = n3 = n4 = n5 = n6 = n7 = 0;;
	
	n1 = int(floor(lat/4)) + 1;
	n2 = int(floor(lon/6)) + 31;
	
	double dLat = 0, dLon = 0;
	int row = 0, col = 0;
	
	double lat1, lon1;
	lat1 = lat - 4*(n1-1);
	lon1 = lon - 6*(n2-31);

	switch (eScale)
	{
	case MS_1000000:
		{
			sprintf(pszMapName, "%c%02d", n1+'A'-1, n2);
		}
		break;
	case MS_500000:
		{
			GetMapSize(eScale, &dLat, &dLon);
			row = 2-int(floor(lat1/dLat));
			col = int(floor(lon1/dLon)) + 1;
			n3  = 2*(row-1) + col;
			sprintf(pszMapName, "%c%02d%c", n1+'A'-1, n2, n3+'A'-1);
		}
		break;
	case MS_250000:
		{
			GetMapSize(eScale, &dLat, &dLon);
			row = 4-int(floor(lat1/dLat));
			col = int(floor(lon1/dLon)) + 1;
			n3  = 4*(row-1) + col;
			sprintf(pszMapName, "%c%02d%02d", n1+'A'-1, n2, n3);
		}
		break;
	case MS_100000:
		{
			GetMapSize(eScale, &dLat, &dLon);
			row = 12-int(floor(lat1/dLat));
			col = int(floor(lon1/dLon)) + 1;
			n3  = 12*(row-1) + col;
			sprintf(pszMapName, "%c%02d%03d", n1+'A'-1, n2, n3);
		}
		break;
	case MS_50000:
		{
			GetMapSize(MS_100000, &dLat, &dLon);
			row = int(floor(lat1/dLat));
			col = int(floor(lon1/dLon));
			lat1 -= row*dLat;
			lon1 -= col*dLon;

			row = 12-row;
			n3  = 12*(row-1) + col+1;

			GetMapSize(MS_50000, &dLat, &dLon);
			row = 2-int(floor(lat1/dLat));
			col = int(floor(lon1/dLon));
			n4  = 2*(row-1) + col+1;

			sprintf(pszMapName, "%c%02d%03d%c", n1+'A'-1, n2, n3, n4+'A'-1);
		}
		break;
	case MS_25000:
		{
			// 10W
			GetMapSize(MS_100000, &dLat, &dLon);
			row = int(floor(lat1/dLat));
			col = int(floor(lon1/dLon));
			lat1 -= row*dLat;
			lon1 -= col*dLon;
			
			row = 12-row;
			n3  = 12*(row-1) + col+1;
			
			// 5W
			GetMapSize(MS_50000, &dLat, &dLon);
			row = int(floor(lat1/dLat));
			col = int(floor(lon1/dLon));

			lat1 -= row*dLat;
			lon1 -= col*dLon;

			row = 2-row;
			n4  = 2*(row-1) + col+1;

			// 2.5W
			GetMapSize(MS_25000, &dLat, &dLon);
			row = int(floor(lat1/dLat));
			col = int(floor(lon1/dLon));

			row = 2-row;
			n5  = 2*(row-1) + col+1;
			
			sprintf(pszMapName, "%c%02d%03d%c%d", n1+'A'-1, n2, n3, n4+'A'-1, n5);	
		}
		break;
	case MS_10000:
		{
			// 10W
			GetMapSize(MS_100000, &dLat, &dLon);
			row = int(floor(lat1/dLat));
			col = int(floor(lon1/dLon));
			lat1 -= row*dLat;
			lon1 -= col*dLon;
			
			row = 12-row;
			n3  = 12*(row-1) + col+1;
			
			// 5W
			GetMapSize(MS_50000, &dLat, &dLon);
			row = int(floor(lat1/dLat));
			col = int(floor(lon1/dLon));
			
			lat1 -= row*dLat;
			lon1 -= col*dLon;
			
			row = 2-row;
			n4  = 2*(row-1) + col+1;
			
			// 2.5W
			GetMapSize(MS_25000, &dLat, &dLon);
			row = int(floor(lat1/dLat));
			col = int(floor(lon1/dLon));

			lat1 -= row*dLat;
			lon1 -= col*dLon;
			
			row = 2-row;
			n5  = 2*(row-1) + col+1;

			// 1W
			GetMapSize(MS_10000, &dLat, &dLon);
			row = int(floor(lat1/dLat));
			col = int(floor(lon1/dLon));

			row = 2-row;
			n6  = 2*(row-1) + col+1;
			
			sprintf(pszMapName, "%c%02d%03d%c%d%d", n1+'A'-1, n2, n3, n4+'A'-1, n5, n6);
		}
		break;
	}
}

bool SPMAPNUMBER_LIB GetMapInfo(const char* pszMapName, MapInfo* info)
{
	int nLen = strlen(pszMapName);
    if (nLen < 1 || nLen > 32) return false;

	int i = 0, n = 0;
	char* p = (char*)pszMapName;
	for (i = 0; i < nLen; i++, p++ )
	{
        if ( !(isdigit(*p) || isalpha(*p) || *p=='(' || *p==')' || *p=='[' || *p==']' || *p=='-') )
            return false;

		if (*p == '-') n++;
	}

    bool bSouthHemi = false;
	char pszNameNorth[32]; memset(pszNameNorth, 0, sizeof(pszNameNorth));
	int n1, n2, n3, n4, n5, n6, n7; // Based 0
	n1 = n2 = n3 = n4 = n5 = n6 = n7 = 0;
	char ch[8];
	MAPSCALE scale = info->scale;

	memset(info, 0, sizeof(MapInfo));

	if (n == 0)
	{
		// Possibly GB new format or GJB new format, the length of map name must 10 or 11
		// if GB new format, else it must range from 3 to 10
		if (nLen < 3 || nLen > 11) 
            return false;

		// The name must be insist of upper alpha and digit
		for (i = 0, p = (char*)pszMapName; i < nLen; i++, p++)
		{
			if (!(isdigit(*p) || isupper(*p)))
                return false;
		}

		p = (char*)pszMapName;
		if (nLen == 11 && *p != 'N' && *p != 'S') 
            return false;

		bSouthHemi = (nLen == 11 && *p == 'S') || (nLen <= 10 && *p == 'S' && isupper(*(p+1)));
		strcpy(pszNameNorth, bSouthHemi?pszMapName+1:pszMapName);

		int nLenNorth = strlen(pszNameNorth);
		if (nLenNorth < 3) 
		{
            return false;
		}
		else if (nLenNorth < 10)
		{
			// GJB New format
			info->format = MF_GJBNEW;
			p = pszNameNorth;

			n1 = p[0] - 'A' + 1;
			strncpy(ch, pszNameNorth+1, sizeof(char)*2); ch[2] = '\0';
			n2 = atoi(ch);

			info->Lat0 = 4*(n1-1 );
			info->Lon0 = 6*(n2-31);

            bool bRet = false;
			int g = 0, row, col;
			double dLat, dLon;

			if (nLenNorth==3)
			{
				// 100W
				info->scale = MS_1000000;
                bRet = true;
			}
			else if (nLenNorth==4 && isupper(p[3]))
			{
				// 50W
				n3 = p[3] - 'A';
                if (n3 < 0 || n3 >= 4) return false;
				info->scale = MS_500000;
				g = 2;
				GetMapSize(info->scale, &dLat, &dLon);
				row = g-n3/g-1;
				col = n3%g;
				info->Lat0 += dLat*row;
				info->Lon0 += dLon*col;
                bRet = true;
			}
			else if (nLenNorth==5)
			{
				// 25W
				strncpy(ch, p+3, sizeof(char)*2); ch[2] = '\0';
				n3 = atoi(ch)-1;
				if (n3 >= 0 && n3 < 16)
				{
					info->scale = MS_250000;
					g = 4;
					GetMapSize(info->scale, &dLat, &dLon);
					row = g-n3/g-1;
					col = n3%g;
					info->Lat0 += dLat*row;
					info->Lon0 += dLon*col;
                    bRet = true;
				}
			}
			else
			{
				// 10W
				strncpy(ch, p+3, sizeof(char)*3); ch[3] = '\0';
				n3 = atoi(ch)-1;
				info->scale = MS_100000;
				g = 12;
				GetMapSize(info->scale, &dLat, &dLon);
				row = g-n3/g-1;
				col = n3%g;
				info->Lat0 += dLat*row;
				info->Lon0 += dLon*col;

				if (nLenNorth==6)
				{
                    bRet = true;
				}
				else
				{
					// 5W
					n4 = p[6] - 'A';
					if (n4 >= 0 && n4 < 4)
					{
						info->scale = MS_50000;
						g = 2;
						GetMapSize(info->scale, &dLat, &dLon);
						row = g-n4/g-1;
						col = n4%g;
						info->Lat0 += dLat*row;
						info->Lon0 += dLon*col;
					}

					if (nLenNorth==7)
					{
                        bRet = true;
					}
					else
					{
						n5 = p[7] - '1';
						if (n5 >= 0 && n5 < 4)
						{
							// 2.5W
							info->scale = MS_25000;
							g = 2;
							GetMapSize(info->scale, &dLat, &dLon);
							row = g-n5/g-1;
							col = n5%g;
							info->Lat0 += dLat*row;
							info->Lon0 += dLon*col;
							
							if (nLenNorth==8)
							{
                                bRet = true;
							}
							else
							{
								// 1W
								n6 = p[8] - '1';
								if (n6 >= 0 && n5 < 4)
								{
									info->scale = MS_10000;
									g = 2;
									GetMapSize(info->scale, &dLat, &dLon);
									row = g-n6/g-1;
									col = n6%g;
									info->Lat0 += dLat*row;
									info->Lon0 += dLon*col;
                                    bRet = true;
								}
							}
						}
					}
				}
			}

            if (!bRet) return false;
			GetMapSize(info->scale, &(info->dLat), &(info->dLon));
		}
		else
		{
			// GB New format
			info->format = MF_GBNEW;
			
			n1 = pszNameNorth[0] - 'A' + 1;
			strncpy(ch, pszNameNorth+1, sizeof(char)*2); ch[2] = '\0';
			n2 = atoi(ch);
			n3 = pszNameNorth[3] - 'A';
			if (n3 < MS_1000000 || n3 > MS_2000)
                return false;
			
			strncpy(ch, pszNameNorth+4, sizeof(char)*3); ch[3] = '\0';
			n4 = atoi(ch);
			
			strncpy(ch, pszNameNorth+7, sizeof(char)*3); ch[3] = '\0';
			n5 = atoi(ch);
			
            n = int(sqrt((double)GetMapTotal((MAPSCALE)n3)));
			if (n4 < 1 || n4 > n || n5 < 1 || n5 > n)
                return false;
			
			info->scale	= (MAPSCALE)n3;
			GetMapSize(info->scale, &(info->dLat), &(info->dLon));
			info->Lat0 = 4*n1		- info->dLat*n4;
			info->Lon0 = 6*(n2-31)	+ info->dLon*(n5-1);
		}	
		
		// Set map information
		strcpy(info->pszName, pszMapName);
	}
	else
	{
		// Possibly GB old format or GJB format
		p = (char*)pszMapName;
        if (*p == 'S' && *(p+1) != '-') bSouthHemi = true;
		strcpy(pszNameNorth, bSouthHemi?pszMapName+1:pszMapName);
		if (bSouthHemi) nLen--;

		if (isupper(pszNameNorth[0]) && pszNameNorth[1] == '-') 
			info->format = MF_GBOLD;
		else						  
			info->format = MF_GJB;

        bool bRet = false;
		int row = 0, col = 0;
		double dLat = 0, dLon = 0;

		if (info->format == MF_GBOLD)
		{
			// GB old format
			char c = 0, c1 = 0;
			sscanf(pszNameNorth, "%c-%d", &c, &n2);
			if (c < 'A' || c > 'V' || n2 < 1 || n2 > 60)
                return false;

			n1 = c - 'A';
			n2--;
			p = strrchr(pszNameNorth, '-') + 1;

			info->Lat0 = 4*n1;
			info->Lon0 = 6*(n2-30);

			switch (n)
			{
			case 1:
				if (nLen == 4)
				{
					// 100W
					info->scale = MS_1000000;
                    bRet = true;
				}
				break;
			case 2:
				{
					// Possibly 50W,25W or 10W
					int g = 0;
					c = *p;
					if (c >= 'A' && c <= 'D')
					{
						// 50W
						info->scale = MS_500000;
						n3 = c - 'A';
						g = 2;
                        bRet = true;
					}
					else if (c == '[')
					{
						// 25W
						info->scale = MS_250000;
						sscanf(pszNameNorth, "%c-%d-[%d]", &c, &n2, &n3);
						n3--;
						if (n3 >= 0 && n3 < 16)
						{
							GetMapSize(info->scale, &dLat, &dLon);
							g = 4;
                            bRet = true;
						}
					}
					else if (isdigit(c))
					{
						// 10W
						info->scale = MS_100000;
						n3 = atoi(p)-1;
						g = 12;
                        bRet = true;
					}
					
					GetMapSize(info->scale, &dLat, &dLon);
					row = g-n3/g-1;
					col = n3%g;
					info->Lat0 += dLat*row;
					info->Lon0 += dLon*col;
				}
				break;
			case 3:
				{
					// Possibly 5W or 1W
					if (*p >= 'A' && *p <= 'D')
					{
						// 5W
						info->scale = MS_50000;
						sscanf(pszNameNorth, "%c-%d-%d-%c", &c, &n2, &n3, &c1);
						n2--; n3--; n4 = c1 - 'A';
						if (n3 >= 0 && n3 < 144)
						{						
							GetMapSize(MS_100000, &dLat, &dLon);
							row = 12-n3/12-1;
							col = n3%12;
							info->Lat0 += dLat*row;
							info->Lon0 += dLon*col;
							
							GetMapSize(MS_50000, &dLat, &dLon);
							row = 2-n4/2-1;
							col = n4%2;
							info->Lat0 += dLat*row;
							info->Lon0 += dLon*col;

                            bRet = true;
						}
					}
					else if (*p == '(')
					{
						// 1W
						info->scale = MS_10000;
						sscanf(pszNameNorth, "%c-%d-%d-(%d)", &c, &n2, &n3, &n4);
						n2--; n3--; n4--;
						if (n3 >= 0 && n3 < 144 && n4 >= 0 && n4 < 64)
						{
							GetMapSize(MS_100000, &dLat, &dLon);
							row = 12-n3/12-1;
							col = n3%12;
							info->Lat0 += dLat*row;
							info->Lon0 += dLon*col;
							
							GetMapSize(MS_10000, &dLat, &dLon);
							row = 8-n4/8-1;
							col = n4%8;
							info->Lat0 += dLat*row;
							info->Lon0 += dLon*col;

                            bRet = true;
						}
					}
				}
				break;
			case 4:
				if (*(p+1) == '\0')
				{
					// Possibly 2.5W or 5000
					if (isdigit(*p))
					{
						// 2.5W
						info->scale = MS_25000;
						sscanf(pszNameNorth, "%c-%d-%d-%c-%d", &c, &n2, &n3, &c1, &n5);
						n2--; n3--; n4 = c1 - 'A'; n5--;
						if (n3 >= 0 && n3 <144 && n4 >= 0 && n4 < 4 && n5 >= 0 && n5 < 4)
						{
							GetMapSize(MS_100000, &dLat, &dLon);
							row = 12-n3/12-1;
							col = n3%12;
							info->Lat0 += dLat*row;
							info->Lon0 += dLon*col;
							
							GetMapSize(MS_50000, &dLat, &dLon);
							row = 2-n4/2-1;
							col = n4%2;
							info->Lat0 += dLat*row;
							info->Lon0 += dLon*col;

							GetMapSize(MS_25000, &dLat, &dLon);
							row = 2-n5/2-1;
							col = n5%2;
							info->Lat0 += dLat*row;
							info->Lon0 += dLon*col;
							
                            bRet = true;
						}
					}
					else if (*p >= 'a' && *p <= 'd')
					{
						// 5000
						info->scale = MS_5000;
						sscanf(pszNameNorth, "%c-%d-%d-(%d)-%c", &c, &n2, &n3, &n4, &c1);
						n2--; n3--; n4--; n5 = c1 - 'a';
						if (n3 >= 0 && n3 <144 && n4 >= 0 && n4 < 64 && n5 >= 0 && n5 < 4)
						{
							GetMapSize(MS_100000, &dLat, &dLon);
							row = 12-n3/12-1;
							col = n3%12;
							info->Lat0 += dLat*row;
							info->Lon0 += dLon*col;
							
							GetMapSize(MS_10000, &dLat, &dLon);
							row = 8-n4/8-1;
							col = n4%8;
							info->Lat0 += dLat*row;
							info->Lon0 += dLon*col;
							
							GetMapSize(MS_5000, &dLat, &dLon);
							row = 2-n5/2-1;
							col = n5%2;
							info->Lat0 += dLat*row;
							info->Lon0 += dLon*col;
							
                            bRet = true;
						}
					}
				}
				break;
			default:
                bRet = false;
				break;
			}

			info->format = MF_GBOLD;
		}
		else
		{
			// GJB format
			sscanf(pszNameNorth, "%d-%d", &n1, &n2);
			info->Lat0 = 4*(n1-1 );
			info->Lon0 = 6*(n2-31);

			switch (n)
			{
			case 1:
				{
					int len = strlen(pszNameNorth);
					if (len == 12)
					{
						char strGB5K[32]; memset(strGB5K, 0, sizeof(strGB5K));
						strncpy(strGB5K, pszNameNorth, len-2);
						int nplus = nplus = pszNameNorth[len-1] - '1';

						MapInfo tInfo;
                        bool bJB2K = (nplus >= 0 && nplus < 9 &&
							GetMapInfo(strGB5K, &tInfo) && tInfo.scale == MS_5000);
						if (bJB2K)
						{
							GetMapSize(MS_2000, &dLat, &dLon);
							row = 3-nplus/3-1;
							col = nplus%3;
							info->Lat0 = tInfo.Lat0 + dLat*row;
							info->Lon0 = tInfo.Lon0 + dLon*col;
							info->scale  = MS_2000;
                            bRet = true;
						}
					}
					else
					{
						info->scale = MS_1000000;
                        bRet = true;
					}
				}
				break;
			case 2:
				{
					int g = 0;
					char* p = strrchr(pszNameNorth, '-') + 1;
					char c = *p;
					if (c >= 'A' && c <= 'D')
					{
						// 50W
						info->scale = MS_500000;
						n3 = c - 'A';
						g = 2;
                        bRet = true;
					}
					else if (c == '[')
					{
						// 25W
						info->scale = MS_250000;
						sscanf(pszNameNorth, "%d-%d-[%d]", &n1, &n2, &n3);
						n3--;
						if (n3 >= 0 && n3 < 16)
						{
							GetMapSize(info->scale, &dLat, &dLon);
							g = 4;
                            bRet = true;
						}
					}
					else if (isdigit(c))
					{
						// 10W
						info->scale = MS_100000;
						n3 = atoi(p)-1;
						g = 12;
                        bRet = true;
					}

					GetMapSize(info->scale, &dLat, &dLon);
					row = g-n3/g-1;
					col = n3%g;
					info->Lat0 += dLat*row;
					info->Lon0 += dLon*col;
				}
				break;
			case 3:
				{
					// 5W
					info->scale = MS_50000;
					char c = 0;
					sscanf(pszNameNorth, "%d-%d-%d-%c", &n1, &n2, &n3, &c);
					n3--;
					if (c >= 'A' && c <= 'D')
					{
						GetMapSize(MS_100000, &dLat, &dLon);
						row = 12-n3/12-1;
						col = n3%12;
						info->Lat0 += dLat*row;
						info->Lon0 += dLon*col;

						n4 = c - 'A';
						GetMapSize(MS_50000, &dLat, &dLon);
						row = 2-n4/2-1;
						col = n4%2;
						info->Lat0 += dLat*row;
						info->Lon0 += dLon*col;

                        bRet = true;
					}
				}
				break;
			case 4:
				{
					// 2.5W
					info->scale = MS_25000;
					char c = 0;
					sscanf(pszNameNorth, "%d-%d-%d-%c-%d", &n1, &n2, &n3, &c, &n5);
					n3--; n4 = c - 'A'; n5--;
					if (n4>-1&&n4<4 && n5>-1&&n5<4)
					{
						GetMapSize(MS_100000, &dLat, &dLon);
						row = 12-n3/12-1;
						col = n3%12;
						info->Lat0 += dLat*row;
						info->Lon0 += dLon*col;
						
						GetMapSize(MS_50000, &dLat, &dLon);
						row = 2-n4/2-1;
						col = n4%2;
						info->Lat0 += dLat*row;
						info->Lon0 += dLon*col;

						GetMapSize(MS_25000, &dLat, &dLon);
						row = 2-n5/2-1;
						col = n5%2;
						info->Lat0 += dLat*row;
						info->Lon0 += dLon*col;

                        bRet = true;
					}
				}
				break;
			case 5:
				{
					info->scale = MS_10000;
					char c = 0;
					sscanf(pszNameNorth, "%d-%d-%d-%c-%d-(%d)", &n1, &n2, &n3, &c, &n5, &n6);
					n3--; n4 = c - 'A';	n5--; n6--;
					if (n4>-1&&n4<4 && n5>-1&&n5<4 && n6>-1&&n6<4)
					{
						GetMapSize(MS_100000, &dLat, &dLon);
						row = 12-n3/12-1;
						col = n3%12;
						info->Lat0 += dLat*row;
						info->Lon0 += dLon*col;
						
						GetMapSize(MS_50000, &dLat, &dLon);
						row = 2-n4/2-1;
						col = n4%2;
						info->Lat0 += dLat*row;
						info->Lon0 += dLon*col;
						
						GetMapSize(MS_25000, &dLat, &dLon);
						row = 2-n5/2-1;
						col = n5%2;
						info->Lat0 += dLat*row;
						info->Lon0 += dLon*col;

						GetMapSize(MS_10000, &dLat, &dLon);
						row = 2-n6/2-1;
						col = n6%2;
						info->Lat0 += dLat*row;
						info->Lon0 += dLon*col;
						
                        bRet = true;
					}
				}
				break;
			case 6:
				{
					info->scale = MS_5000;
					char c1 = 0, c2 = 0;
					sscanf(pszNameNorth, "%d-%d-%d-%c-%d-(%d)-(%c)", &n1, &n2, &n3, &c1, &n5, &n6, &c2);
					n3--; n4 = c1-'A'; n5--; n6--; n7 = c2-'a';
					if (n4>-1&&n4<4 && n5>-1&&n5<4 && n6>-1&&n6<4 && n7>-1&&n7<4)
					{
						GetMapSize(MS_100000, &dLat, &dLon);
						row = 12-n3/12-1;
						col = n3%12;
						info->Lat0 += dLat*row;
						info->Lon0 += dLon*col;
						
						GetMapSize(MS_50000, &dLat, &dLon);
						row = 2-n4/2-1;
						col = n4%2;
						info->Lat0 += dLat*row;
						info->Lon0 += dLon*col;
						
						GetMapSize(MS_25000, &dLat, &dLon);
						row = 2-n5/2-1;
						col = n5%2;
						info->Lat0 += dLat*row;
						info->Lon0 += dLon*col;
						
						GetMapSize(MS_10000, &dLat, &dLon);
						row = 2-n6/2-1;
						col = n6%2;
						info->Lat0 += dLat*row;
						info->Lon0 += dLon*col;
						
						GetMapSize(MS_5000, &dLat, &dLon);
						row = 2-n7/2-1;
						col = n7%2;
						info->Lat0 += dLat*row;
						info->Lon0 += dLon*col;

                        bRet = true;
					}
				}
				break;
			default:
                bRet = false;
				break;
			}

            if (!bRet) return false;
			info->format = MF_GJB;
		}
		GetMapSize(info->scale, &(info->dLat), &(info->dLon));
	}

	if (info->Lat0 < -90 || info->Lat0 > 90 || info->Lon0 < -180 || info->Lon0 > 360)
        return false;

	strcpy(info->pszName, pszNameNorth);
	if (bSouthHemi) 
	{
		info->Lat0 = -(info->Lat0+info->dLat);
		sprintf(info->pszName, "S%s", pszNameNorth);
	}

    return true;
}

bool SPMAPNUMBER_LIB GetMapInfo(double lat, double lon, MapInfo* info)
{
	if (info->format < MF_GBNEW	  || info->format > MF_GJBNEW	||
		info->scale  < MS_1000000 || info->scale  > MS_2000		||
		lat < -90  || lat > 90    || lon < -180 || lon > 360 )
        return false;

    bool bSouth = (lat < 0);
	if (bSouth) lat = -lat;
	if (lon > 180) lon -= 360;

	int fo = info->format;
	MAPSCALE  so = info->scale;

	switch (info->format)
	{
	case MF_GBNEW:
		{
			GetGBNewMapName(info->scale, lat, lon, info->pszName);
		}
		break;
	case MF_GBOLD:
		{
			GetGBOldMapName(info->scale, lat, lon, info->pszName);
		}
		break;
	case MF_GJB:
		{
			GetGJBMapName(info->scale, lat, lon, info->pszName);
		}
		break;
	case MF_GJBNEW:
		{
			GetGJBNewMapName(info->scale, lat, lon, info->pszName);
		}
		break;
	default:
		break;
	}

	char pszMapName[32]; memset(pszMapName, 0, sizeof(pszMapName));
	if (bSouth) sprintf(pszMapName, "S%s", info->pszName);
	else		strcpy(pszMapName, info->pszName);
	
	return GetMapInfo(pszMapName, info) && info->format == fo && info->scale == so;
}

bool SPMAPNUMBER_LIB ConvertMapName(const char* pszNameIn, int nOutFormat, char* pszNameOut)
{
	MapInfo info;
	if (!GetMapInfo(pszNameIn, &info))
        return false;

	info.format = nOutFormat;
	if (!GetMapInfo(info.Lat0+info.dLat/2, info.Lon0+info.dLon/2, &info))
        return false;

	strcpy(pszNameOut, info.pszName);

    return true;
}

int  SPMAPNUMBER_LIB GetMapTotal(MAPSCALE scale)
{
	int total = 0;
	switch (scale)
	{
	case MS_1000000:total = 1;		break;
	case MS_500000:	total = 4;		break; // 2   * 2
	case MS_250000:	total = 16;		break; // 4   * 4
	case MS_100000:	total = 144;	break; // 12  * 12
	case MS_50000:	total = 576;	break; // 24  * 24
	case MS_25000:	total = 2304;	break; // 48  * 48
	case MS_10000:	total = 9216;	break; // 96  * 96
	case MS_5000:	total = 36864;	break; // 192 * 192
	case MS_2000:	total = 331776;	break; // 576 * 576
	default:		total = 0;		break;
	}
	return total;
}

void SPMAPNUMBER_LIB GetMapSize(MAPSCALE scale, double* lfLatDelta, double* lfLonDelta)
{
	switch(scale)
	{
	case MS_1000000:
		{
			*lfLatDelta = 4.0f;     // 4
			*lfLonDelta = 6.0f;     // 6
		}
		break;
	case MS_500000:
		{
			*lfLatDelta = 2.0f;     // 2
			*lfLonDelta = 3.0f;     // 3	
		}
		break;
	case MS_250000:
		{
			*lfLatDelta = 1.0f;     // 1
			*lfLonDelta = 1.5f;     // 1 30'		
		}
		break;
	case MS_100000:
		{
			*lfLatDelta = 0.33333333333333;	// 20'
			*lfLonDelta = 0.5;				// 30'
		}
		break;
	case MS_50000:
		{
			*lfLatDelta = 0.16666666666667;	// 10'
			*lfLonDelta = 0.25;				// 15'
		}
		break;
	case MS_25000:
		{
			*lfLatDelta = 0.08333333333333;	// 5'
			*lfLonDelta = 0.125;			// 7'30"
		}
		break;
	case MS_10000:
		{
			*lfLatDelta = 0.04166666666667;	// 2'30"
			*lfLonDelta = 0.0625;			// 3'45"
		}
		break;
	case MS_5000:
		{
			*lfLatDelta = 0.02083333333333;	// 1'15"
			*lfLonDelta = 0.03125;			// 1'52.5"
		}
		break;
	case MS_2000:
		{
			*lfLatDelta = 0.00694444444444; // 25"
			*lfLonDelta = 0.01041666666667; // 37.5"
		}
		break;
	default:
		{
			*lfLatDelta = 0.0;
			*lfLonDelta = 0.0;
		}
		break;
	}
}

int  SPMAPNUMBER_LIB ScaleIndexToValue(MAPSCALE scale)
{
	int nScaleValue = 0;
	switch (scale)
	{
	case MS_1000000:nScaleValue = 1000000; break;
	case MS_500000: nScaleValue =  500000; break;
	case MS_250000:	nScaleValue =  250000; break;
	case MS_100000:	nScaleValue =  100000; break;
	case MS_50000:	nScaleValue =   50000; break;
	case MS_25000:	nScaleValue =   25000; break;
	case MS_10000:	nScaleValue =   10000; break;
	case MS_5000:	nScaleValue =    5000; break;
	case MS_2000:	nScaleValue =    2000; break;
	default:		nScaleValue =       0; break;
	}

	return nScaleValue;
}

/////////////////////////////////////////////////////////////////
/// class CStdMap
/////////////////////////////////////////////////////////////////
MapInfo* GetMapsByRange(MapInfo infoIn, int* n)
{
    MapInfo* m_pMapInfo;
    int m_nMapInfo;

    double MinLat, MaxLat, MinLon, MaxLon;
    MinLat = (infoIn.dLat > 0 ? infoIn.Lat0 : infoIn.Lat0+infoIn.dLat);
    MaxLat = (infoIn.dLat > 0 ? infoIn.Lat0+infoIn.dLat : infoIn.Lat0);
    MinLon = (infoIn.dLon > 0 ? infoIn.Lon0 : infoIn.Lon0+infoIn.dLon);
    MaxLon = (infoIn.dLon > 0 ? infoIn.Lon0+infoIn.dLon : infoIn.Lon0);

    if (MinLat * MaxLat < 0)
    {
        MapInfo info;
        info.format = infoIn.format;
        info.scale  = infoIn.scale;
        info.Lon0	= MinLon;
        info.dLon	= fabs(infoIn.dLat);;

        info.Lat0	= 0;
        info.dLat	= MaxLat;

        int n1 = 0, n2 = 0;
        MapInfo* pMapNorth = GetMapsByRange(info, &n1);

        info.Lat0	= MinLat;
        info.dLat	= -MinLat;
        MapInfo* pMapSouth = GetMapsByRange(info, &n2);

        m_pMapInfo = new MapInfo[n1+n2];
        memcpy(m_pMapInfo,		pMapSouth, sizeof(MapInfo)*n2);
        memcpy(m_pMapInfo+n2,	pMapNorth, sizeof(MapInfo)*n1);

        m_nMapInfo = n1+n2;

        ReleaseBuffer(pMapSouth);
        ReleaseBuffer(pMapNorth);
    }
    else
    {
        bool bSouth = (MaxLat < 0);
        if (bSouth)
        {
            double tmp = -MinLat; MinLat = -MaxLat; MaxLat = tmp;
        }

        MapInfo info;
        info.format = MF_GBNEW;
        info.scale  = infoIn.scale;

        GetMapInfo(MinLat, MinLon, &info);
        MinLat = info.Lat0;
        MinLon = info.Lon0;
        GetMapInfo(MaxLat, MaxLon, &info);
        MaxLat = info.Lat0 + info.dLat;
        MaxLon = info.Lon0 + info.dLon;

        int row = int((MaxLat-MinLat)/info.dLat+0.5);
        int col = int((MaxLon-MinLon)/info.dLon+0.5);

        m_nMapInfo = row*col;
        m_pMapInfo = new MapInfo[m_nMapInfo];
        memset(m_pMapInfo, 0, sizeof(MapInfo)*m_nMapInfo);

        int i, j;
        MinLat += info.dLat/2;
        MinLon += info.dLon/2;

        for (i = 0; i < m_nMapInfo; i++)
        {
            m_pMapInfo[i].format = infoIn.format;
            m_pMapInfo[i].scale  = infoIn.scale;
        }

        double Lat, Lon;
        double LatTmp;
        m_nMapInfo = 0;
        for (i = 0, LatTmp = MinLat; i < row; i++, LatTmp+=info.dLat)
        {
            Lat = bSouth?-LatTmp:LatTmp;
            for (j = 0, Lon = MinLon; j < col; j++, Lon+=info.dLon)
            {
                if (GetMapInfo(Lat, Lon, m_pMapInfo+m_nMapInfo))
                    m_nMapInfo++;
            }
        }
    }

    *n = m_nMapInfo;
    return m_pMapInfo;
}

void ReleaseBuffer(MapInfo* m_pMapInfo)
{
    if (m_pMapInfo != NULL)
    {
        delete [] m_pMapInfo;
        m_pMapInfo = NULL;
    }
}
